package adc.app.ui.wicket;

import java.io.Serializable;

import org.apache.wicket.IClusterable;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
import org.apache.wicket.feedback.ContainerFeedbackMessageFilter;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.PasswordTextField;
import org.apache.wicket.markup.html.form.SimpleFormComponentLabel;
import org.apache.wicket.markup.html.form.validation.EqualPasswordInputValidator;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.model.ResourceModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import adc.app.spec.BsException;
import adc.app.spec.IUser;
import adc.app.spec.IUserBs;
import adc.app.spec.IUserContext;
import adc.app.ui.wicket.model.SpringBeanModel;
import adc.app.ui.wicket.security.AuthenticationRequired;

@AuthenticationRequired
public class ChangePasswordPanel extends Panel {

	private static final long serialVersionUID = 1L;
	
	private static final Logger LOG = LoggerFactory.getLogger(ChangePasswordPanel.class);

    public static interface IPasswordChangedCallback extends IClusterable {
		public abstract void onPasswordChanged(AjaxRequestTarget target);
	}
	
	public static interface IQuitChangePasswordCallback extends IClusterable {
		public abstract void onQuitChangePassword(AjaxRequestTarget target);
	}
	
	private final ChangePasswordLink changePassLnk;
	private final QuitChangePasswordLink quitLnk;
	private final AlertFeedbackPanel fdb;

	public ChangePasswordPanel(String id, IModel<IUser> user) {
		super(id, user);
		final Form<ChangePassword> form = new Form<ChangePassword>("form", 
				new CompoundPropertyModel<ChangePassword>(new ChangePassword()));
		add(form);
		
		fdb = new AlertFeedbackPanel("fdb", new ContainerFeedbackMessageFilter(form));
		add(fdb);
		
		final PasswordTextField oldPassFld = new PasswordTextField("oldPass");
		oldPassFld.setLabel(new ResourceModel(IMsgs.OLD_PASSWORD));
		oldPassFld.setRequired(true);
		form.add(oldPassFld).add(new SimpleFormComponentLabel("oldPassLbl", oldPassFld));
		
		final PasswordTextField newPassFld = new PasswordTextField("newPass");
		newPassFld.setLabel(new ResourceModel(IMsgs.NEW_PASSWORD));
		newPassFld.setRequired(true);
		form.add(newPassFld).add(new SimpleFormComponentLabel("newPassLbl", newPassFld));
		
		final PasswordTextField confirmPassFld = new PasswordTextField("confirmPass");
		confirmPassFld.setLabel(new ResourceModel(IMsgs.CONFIRM_PASSWORD));
		confirmPassFld.setRequired(true);
		form.add(confirmPassFld).add(new SimpleFormComponentLabel("confirmPassLbl", confirmPassFld));
		
		form.add(new EqualPasswordInputValidator(newPassFld, confirmPassFld));
		
		form.add(changePassLnk = new ChangePasswordLink("changePass", form));
		changePassLnk.add(new Label("lbl", new ResourceModel(IMsgs.CHANGE_PASSWORD)));
		
		form.add(quitLnk = new QuitChangePasswordLink("quit"));
		quitLnk.add(new Label("lbl", new ResourceModel(IMsgs.QUIT)));
	}
	
	public ChangePasswordPanel(String id) {
		this(id, new PropertyModel<IUser>(new SpringBeanModel<IUserContext>(IUserContext.class), "user"));
	}
	
	public IPasswordChangedCallback getPasswordChangedCallback() {
		return changePassLnk.callback;
	}
	
	public ChangePasswordPanel setPasswordChangedCallback(IPasswordChangedCallback callback) {
		changePassLnk.callback = callback;
		return this;
	}
	
	public IQuitChangePasswordCallback getQuitChangePasswordCallback() {
		return quitLnk.callback;
	}
	
	public ChangePasswordPanel setQuitCallback(IQuitChangePasswordCallback callback) {
		quitLnk.callback = callback;
		return this;
	}
	
	private static final class ChangePassword implements Serializable {
		
		private static final long serialVersionUID = 1L;
		
		private String oldPass, newPass, confirmPass;

		public String getOldPass() {
			return oldPass;
		}

		public void setOldPass(String oldPass) {
			this.oldPass = oldPass;
		}

		public String getNewPass() {
			return newPass;
		}

		public void setNewPass(String newPass) {
			this.newPass = newPass;
		}

		public String getConfirmPass() {
			return confirmPass;
		}

		public void setConfirmPass(String confirmPass) {
			this.confirmPass = confirmPass;
		}
		
	}
	
	private static final class ChangePasswordLink extends AjaxSubmitLink {
		
		private static final long serialVersionUID = 1L;
		private IPasswordChangedCallback callback;
		
		@SpringBean
		private IUserBs userBS;

		private ChangePasswordLink(String id, Form<?> form) {
			super(id, form);
		}

		@Override
		protected void onError(AjaxRequestTarget target, Form<?> form) {
			target.addComponent(this.findParent(ChangePasswordPanel.class).fdb);
		}
		
		@Override
		protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
			ChangePasswordPanel cpp = this.findParent(ChangePasswordPanel.class);
			IUser user = (IUser) cpp.getDefaultModelObject();
			ChangePassword cp = (ChangePassword) form.getModelObject();
			if (!userBS.verifyPassword(user, cp.getOldPass())) {
				form.error(cpp.getString(IMsgs.OLD_PASSWORD_ERR));
				return;
			}
			try {
				userBS.changePassword(user, cp.getNewPass());
			} catch (BsException e) {
				LOG.error(e.getMessage(), e);
				form.error(cpp.getString(IMsgs.INTERNAL_ERROR));
			}
			if (callback != null) {
				callback.onPasswordChanged(target);
			}
		}
		
	}
	
	private static final class QuitChangePasswordLink extends AjaxLink<Object> {

		private static final long serialVersionUID = 1L;
		
		private IQuitChangePasswordCallback callback;

		private QuitChangePasswordLink(String id) {
			super(id);
		}

		@Override
		public void onClick(AjaxRequestTarget target) {
			if (callback != null) {
				callback.onQuitChangePassword(target);
			}
		}
		
	}
}
